﻿using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using WebAPI_Demo.Filter;
using WebAPI_Demo.Models;
using WebAPI_Demo.Models.Database;
using WebAPI_Demo.Services;

namespace WebAPI_Demo.Controllers
{
    //api/Good/方法名字
    [Route("api/[controller]/[action]")]
    [ApiController]
    public class GoodController : ControllerBase
    {
        //定义数据库上下文
        private readonly Store_2022Context _db;
        //定义服务类
        private readonly IDataServices _dataService;
        /// <summary>
        // 定义单例服务
        /// </summary>
        private readonly ISingletonServices _singletonServices;
        private readonly ITransientService _transientService;
        private readonly IScopedService _scopedService;


        /// <summary>
        /// 依赖注入
        /// 构造方法 构造注入（其中一个方法）
        /// 初始化数据库上下文
        /// </summary>
        /// 商品控制器对象 依赖于 Store_2022Context数据库上下文对象
        public GoodController(Store_2022Context db, IDataServices dataService, ISingletonServices singletonServices, ITransientService transientService, IScopedService scopedService)
        {
            //把构造方法里面db赋值给_db
            _db = db;
            _dataService = dataService;
            _singletonServices = singletonServices;
            _transientService = transientService;
            _scopedService = scopedService;

            //依赖注入 解决一个问题
            //不需要自己去实例化对象 他会交给程序算法去帮我们创建实例化对象 获取过来就能使用
            //控制反转IOC  从哪里获取 IOC容器 获取过来就能使用

            //1、对依赖进行定义配置StartUp

            //2、使用的时候 获取这个对象 获取回来的就是实例化 好的对象
            //在构造方法获取Store_2022Context db 
        }

        /// <summary>
        /// 新增产品
        /// </summary>
        /// <param name="good"></param>
        /// <returns></returns>
        /// 支持的请求方式
        //[HttpGet] 当参数是一个对象的时候 swagger不支持GET
        [HttpPost]
        //访问权限 返回数据类型 方法名字 （请求（接收）的参数【（Good参数的类型 参数的名字）】）
        //api/Good/AddGood
        public string AddGood(Good good)
        {
            //执行后端业务
            //上下文.表名.操作（参数）
            _db.Goods.Add(good);
            //保存数据库更改
            var row = _db.SaveChanges();
            if (row > 0)
                return "新增成功";
            return "新增失败";
        }

        /// <summary>
        /// 新增产品 使用自定义请求类
        /// </summary>
        [HttpPost]
        public string AddGood2(AddGoodRequest request)
        {
            //传入参数规则
            //    //拿到了请求类
            //    //需求 判断我的商品名称 不能为空 如果为空 要返回提示给前端
            //    if (string.IsNullOrEmpty(request.Name))
            //        return "商品名称不能为空";

            //    //判断分类Id不能为0
            //    if (request.CateId == 0)
            //        return "请选择分类";

            //    //价格必须>0
            //    if (request.Price <= 0)
            //        return "价格必须>0";
            //1、定义模型规则
            //模型状态是否验证通过属性 
            if (!ModelState.IsValid)
            {
                // ModelState[ModelState.Keys.FirstOrDefault()].Errors.FirstOrDefault();
                return "数据错误";
            }


            //请求类 转换 成 数据的类
            var good = new Good
            {
                Name = request.Name,
                CateId = request.CateId,
                Price = request.Price,
                Cover = request.Cover,
                Stock = request.Stock,
                CreateTime = DateTime.Now,
                UpdateTime = DateTime.Now
            };
            //新增数据
            //上下文.表名.操作方法
            _db.Goods.Add(good);
            //保存更改
            var row = _db.SaveChanges();
            if (row > 0)
                return "新增成功";
            return "新增失败";
        }

        /// <summary>
        /// 新增产品 使用get参数 name  cateId price stock cover
        ///        url ?name=....&cateId=xxxx&price=xxxx&
        /// </summary>
        [HttpGet]
        public string AddGood3(string name, int cateId, decimal price, int stock, string cover)
        {
            //后端业务逻辑  

            //把单个的请求参数  转换成 数据的类
            var good = new Good
            {
                Name = name,
                CateId = cateId,
                Cover = cover,
                Price = price,
                Stock = stock,
                CreateTime = DateTime.Now,
                UpdateTime = DateTime.Now,
            };
            _db.Goods.Add(good);
            var row = _db.SaveChanges();
            if (row > 0)
                return "新增成功";
            return "新增失败";
        }

        //[HttpGet]
        //一般查询用GET
        //增删改 
        //[HttpPost]

        //分类表  练习 通过3种方式实现分类数据的添加接口
        /// <summary>
        /// 新增分类
        /// </summary>
        /// <param name="category"></param>
        /// <returns></returns>
        [HttpPost]
        public string AddCategory1(Category category)
        {
            _db.Categories.Add(category);
            var row = _db.SaveChanges();
            if (row > 0)
                return "新增成功";
            return "新增失败";
        }
        /// <summary>
        /// 新增分类 自定义请求类
        /// </summary>
        /// <returns></returns>
        [HttpPost]
        public string AddCategory2(AddCategory2Request request)
        {
            //转换
            var cate = new Category { CateName = request.CateName };
            _db.Categories.Add(cate);
            var row = _db.SaveChanges();
            if (row > 0)
                return "新增成功";
            return "新增失败";
        }
        /// <summary>
        /// 新增分类 通过Get参数
        /// </summary>
        /// <returns></returns>
        [HttpGet]
        [HttpPost]
        public string AddCatrgory3(string name)
        {
            var cate = new Category()
            {
                CateName = name
            };
            _db.Categories.Add(cate);
            var row = _db.SaveChanges();
            if (row > 0)
                return "新增成功";
            return "新增失败";
        }

        //sql update good set name='xxx' , cate=1 where id=xxx
        /// <summary>
        /// 更新商品接口
        /// </summary>   前端传过来的参数 应该有什么？条件 哪个商品 ，更新的值是什么
        [HttpPost]
        public string UpdateGood(Good good)
        {
            //更新的业务逻辑
            //查询Id为请求过来的商品的 商品 查询出来 查询单个商品
            var model = _db.Goods.FirstOrDefault(x => x.Id == good.Id);
            if (good == null)
                return "商品不存在";

            //对商品的字段进行赋值
            model.Name = good.Name;
            model.Stock = good.Stock;
            model.Price = good.Price;
            model.CateId = good.CateId;
            model.Cover = good.Cover;

            //更新操作
            //上下文.表名.操作方法
            _db.Goods.Update(model);
            //保存更改
            var row = _db.SaveChanges();
            if (row > 0)
                return "更新成功";
            return "更新失败";
        }

        //练习  使用自定义请求类 实现 商品 更新
        /// <summary>
        /// 更新商品
        /// </summary>
        /// <returns></returns>
        [HttpPost]
        public string UpdateGood2(UpdateGood2 request)
        {
            //把需要更新的商品 查询出来
            var good = _db.Goods.FirstOrDefault(x => x.Id == request.Id);
            //空处理
            if (good == null)
                return "商品不存在";
            //更新字段
            good.Name = request.Name;
            good.Cover = request.Cover;
            good.CateId = request.CateId;
            good.Price = request.Price;

            _db.Goods.Update(good);
            var row = _db.SaveChanges();
            if (row > 0)
                return "更新成功";
            return "更新失败";
        }

        /// <summary>
        /// 删除商品 删除哪个商品 Id删除
        /// </summary>
        /// <returns></returns>
        [HttpPost]
        public string DeleteGood(int id)
        {
            //删除业务

            var good = _db.Goods.FirstOrDefault(x => x.Id == id);
            if (good == null)
                return "商品不存在";

            //删除
            //上下文.表名.操作方法
            _db.Goods.Remove(good);
            var row = _db.SaveChanges();
            if (row > 0)
                return "删除成功";
            return "删除失败";
        }

        //查询商品 返回前端 商品的数据 根据商品名称查询数据
        /// <summary>
        /// 查询商品列表
        /// </summary>
        /// <returns></returns>
        [HttpGet]
        public List<Good> GetList(string name, int cateId)
        {
            //上下文.表名.操作 所有的商品数据 
            var goods = _db.Goods
                 //条件查询
                 .Where(x => x.Name == name)
                 .ToList();

            //当我名称输入空，查询全商品
            //当分类Id为0,查询全部商品 否则 查询分类Id为cateId商品

            //先获取商品的查询
            var goods1 = _db.Goods.AsQueryable();
            if (!string.IsNullOrEmpty(name))
                //条件查询
                return goods1.Where(x => x.Name == name).ToList();

            var goods2 = _db.Goods.AsQueryable();
            if (!string.IsNullOrEmpty(name))
                //条件查询
                goods2 = goods2.Where(x => x.Name.Contains(name));
            if (cateId > 0)
                goods2 = goods2.Where(x => x.CateId == cateId);
            return goods2.ToList();
        }

        /// <summary>
        /// 查询单个商品 使用Id查询
        /// </summary>
        /// <param name="id"></param>
        /// <returns></returns>
        [HttpGet]
        public Good GetGood(int id)
        {
            //查询出来的商品结果
            var good = _db.Goods.FirstOrDefault(x => x.Id == id);
            return good;
        }

        //查询指定商品的价格
        /// <summary>
        /// 
        /// </summary>
        /// <param name="id"></param>
        /// <returns></returns>
        [HttpGet]
        public decimal GetGoodPrice(int id)
        {
            //业务逻辑
            var good = _db.Goods.FirstOrDefault(x => x.Id == id);
            return good.Price;
        }

        //练习 写接口 返回所有分类


        /// <summary>
        /// 返回连表后的模型数据
        /// </summary>
        /// <returns></returns>
        [HttpPost]
        public List<GoodModel> GetGoodAllList3(string keyword, int cateId)
        {
            //获取商品操作       转换为待执行SQL语句
            var goods = _db.Goods.AsQueryable();
            //如果查询的分类Id>0 
            if (cateId > 0)
                goods = goods.Where(x => x.CateId == cateId);

            //如果查询的关键字不为空
            if (!string.IsNullOrEmpty(keyword))
                goods = goods.Where(x => x.Name.Contains(keyword));

            //表连接                连接的表      主表的连接字段外键 被连接表字段主键   把两个表的字段合并
            var list = goods.Join(_db.Categories, x => x.CateId, y => y.Id, (x, y) => new GoodModel
            {
                Name = x.Name,
                CateId = x.CateId,
                CategoryName = y.CateName,
                Cover = x.Cover,
                Id = x.Id,
                Price = x.Price,
                Stock = x.Stock
            }).ToList();
            return list;
        }


        //        //怎么写一个接口
        //        //接口有什么内容
        //        //1、支持请求方式
        //        //[HttpPost]  增改删 一般情况
        //        //[HttpGet]   查
        //        [HttpPost]
        //        //2、方法访问权限 public
        //        //3、返回类型 根据需求决定
        //        //  查询数据 数据的类型
        //        //  增改删 返回一个消息 字符串
        //        //4、方法名 决定的是 调用的方法url api/控制器名/方法名
        //        //5、参数 根据需求决定
        //        public 返回类型 方法的名字(参数)
        //        {
        //            //6、执行逻辑
        //            //业务逻辑代码
        //            //7、返回的数据
        ////            return 数据;
        //        }


        /// <summary>
        /// 
        /// </summary>
        //[HttpPost]
        //public void GetData()
        //{
        //    _dataService.GetData();
        //}
        //方法注入IOC容器获取对象第二种方式
        [HttpPost]
        public string GetData([FromServices] IDataServices dataService2)
        {
            //这个对象是控制器里面获取的
            //_dataService
            //这个对象是通过方法注入获取的
            //dataService2
            //判断这两个是不是同一个对象 GetHashCode 获取对象的HashCode 不同的对象Hashcode是不一样的 
            return "_dataService的hashCode:" + _dataService.GetHashCode() + "    dataService2:" + dataService2.GetHashCode();
        }

        //1、添加接口
        /// <summary>
        /// 单例 对象创建后 每次访问都是一样对象
        /// </summary>
        /// <returns></returns>
        [HttpPost]
        public string Singleton()
        {

            //这个对象是控制器里面获取的
            //_dataService
            //这个对象是通过方法注入获取的
            //dataService2
            //判断这两个是不是同一个对象 GetHashCode 获取对象的HashCode 不同的对象Hashcode是不一样的 
            return "_singletonServices的hashCode:" + _singletonServices.GetHashCode();
        }
        /// <summary>
        /// 瞬时的 每次获取都是新的对象
        /// </summary>
        /// <param name="transientService2"></param>
        /// <returns></returns>
        [HttpPost]
        public string Transient([FromServices] ITransientService transientService2)
        {

            //判断这两个是不是同一个对象 GetHashCode 获取对象的HashCode 不同的对象Hashcode是不一样的 
            return "1的hashCode:" + _transientService.GetHashCode() + "2的hashCode:" + transientService2.GetHashCode();
        }
        /// <summary>
        /// 瞬时的 每次获取都是新的对象
        /// </summary>
        /// <param name="scopedService"></param>
        /// <returns></returns>
        [HttpPost]
        public string Scoped([FromServices] IScopedService scopedService)
        {
            //判断这两个是不是同一个对象 GetHashCode 获取对象的HashCode 不同的对象Hashcode是不一样的 
            return "1的hashCode:" + _scopedService.GetHashCode() + "2的hashCode:" + scopedService.GetHashCode();
        }
    }
}
